﻿using Microsoft.SharePoint;
using AgileShare.Framework.Core;
using AgileShare.Framework.SiteProvisioning.Definitions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AgileShare.Framework.SiteProvisioning.Helpers
{
	public static class ContentTypeDefinitionHelper
	{
		/// <summary>
		/// Ensures the content types.
		/// </summary>
		/// <param name="contentTypeDefinitions">The content type definitions.</param>
		/// <param name="site">The site.</param>
		/// <param name="updateIfExists">if set to <c>true</c> [update if exists].</param>
		public static void EnsureContentTypes(IEnumerable<ContentTypeDefinition> contentTypeDefinitions, SPSite site, bool updateIfExists = false, bool updateChildren = false)
		{
			foreach (ContentTypeDefinition contentTypeDefinition in contentTypeDefinitions)
			{
				EnsureContentType(contentTypeDefinition, site, updateIfExists, updateChildren);
			}
		}

		/// <summary>
		/// Ensures the type of the content.
		/// </summary>
		/// <param name="definition">The definition.</param>
		/// <param name="site">The site.</param>
		/// <param name="updateIfExists">if set to <c>true</c> [update if exists].</param>
		/// <returns></returns>
		public static SPContentType EnsureContentType(ContentTypeDefinition definition, SPSite site, bool updateIfExists = false, bool updateChildren = false)
		{
			SPWeb web = site.RootWeb;
			SPContentTypeCollection contentTypeCollection = web.ContentTypes;

			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Information,
				"Ensuring Content Type '{0}'; ID: '{1}';", definition.Name, definition.Id);

			SPContentType contentType = contentTypeCollection[definition.Id];

			try
			{
				if (contentType == null)
				{
					contentType = new SPContentType(definition.Id, contentTypeCollection, definition.Name);
					contentTypeCollection.Add(contentType);

					UpdateContentType(definition, site, updateChildren);
				}
				else if (updateIfExists)
				{
					UpdateContentType(definition, site, updateChildren);
				}
				TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SPFieldHelper, TraceProviderSeverity.Monitorable,
					"Successfully ensured Content Type '{0}'; ID: '{1}';", definition.Name, definition.Id);
			}
			catch (Exception ex)
			{
				TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.CriticalError, ex,
					"Failed to ensure Content Type '{0}'; ID: '{1}';", definition.Name, definition.Id);
			}

			return contentType;
		}

		/// <summary>
		/// Updates the type of the content.
		/// </summary>
		/// <param name="definition">The definition.</param>
		/// <param name="web">The web.</param>
		/// <returns></returns>
		public static SPContentType UpdateContentType(ContentTypeDefinition definition, SPSite site, bool updateChildren = false)
		{
			SPWeb web = site.RootWeb;
			SPContentTypeCollection contentTypeCollection = web.ContentTypes;

			SPContentType contentType = contentTypeCollection[definition.Id];

			if (contentType != null)
			{
				if (!string.IsNullOrEmpty(definition.Name)) contentType.Name = definition.Name;
				if (definition.Hidden.HasValue) contentType.Hidden = definition.Hidden.Value;
				if (definition.ReadOnly.HasValue) contentType.ReadOnly = definition.ReadOnly.Value;

				if (definition.Sealed.HasValue) contentType.Sealed = definition.Sealed.Value;
				if (!string.IsNullOrEmpty(definition.Description)) contentType.Description = definition.Description;
				if (!string.IsNullOrEmpty(definition.Group)) contentType.Group = definition.Group;

				foreach (FieldLinkDefinition fieldLinkDefinition in definition.FieldLinkDefinitions)
				{
					SPFieldLink fieldLink = null;
					if (contentType.Fields.Contains(fieldLinkDefinition.Id))
					{
						fieldLink = contentType.FieldLinks[fieldLinkDefinition.Id];
					}
					else if (web.Fields.Contains(fieldLinkDefinition.Id) && !contentType.Fields.Contains(fieldLinkDefinition.Id))
					{
						SPField field = web.Fields[fieldLinkDefinition.Id];
						fieldLink = new SPFieldLink(field);
						contentType.FieldLinks.Add(fieldLink);
					}

					if (fieldLink != null)
					{
						if (!string.IsNullOrEmpty(fieldLinkDefinition.DisplayName)) fieldLink.DisplayName = fieldLinkDefinition.DisplayName;
						if (fieldLinkDefinition.Hidden.HasValue) fieldLink.Hidden = fieldLinkDefinition.Hidden.Value;
						if (fieldLinkDefinition.ReadOnly.HasValue) fieldLink.ReadOnly = fieldLinkDefinition.ReadOnly.Value;
						if (fieldLinkDefinition.Required.HasValue) fieldLink.Required = fieldLinkDefinition.Required.Value;
						if (fieldLinkDefinition.ShowInDisplayForm.HasValue) fieldLink.ShowInDisplayForm = fieldLinkDefinition.ShowInDisplayForm.Value;
					}
				}
				// TODO: Should "throw exception" parameter be passed in the UpdateContentType method?
				contentType.Update(updateChildren, false);

				// More properties to implement.
				//if (definition.RequireClientRenderingOnNew.HasValue) contentType.RequireClientRenderingOnNew = definition.RequireClientRenderingOnNew.Value;
				//if (!string.IsNullOrEmpty(definition.DisplayFormTemplateName)) contentType.DisplayFormTemplateName = definition.DisplayFormTemplateName;
				//if (!string.IsNullOrEmpty(definition.DisplayFormUrl)) contentType.DisplayFormUrl = definition.DisplayFormUrl;
				//if (!string.IsNullOrEmpty(definition.DocumentTemplate)) contentType.DocumentTemplate = definition.DocumentTemplate;
				//if (!string.IsNullOrEmpty(definition.EditFormTemplateName)) contentType.EditFormTemplateName = definition.EditFormTemplateName;
				//if (!string.IsNullOrEmpty(definition.EditFormUrl)) contentType.EditFormUrl = definition.EditFormUrl;				
				//if (!string.IsNullOrEmpty(definition.MobileDisplayFormUrl)) contentType.MobileDisplayFormUrl = definition.MobileDisplayFormUrl;
				//if (!string.IsNullOrEmpty(definition.MobileEditFormUrl)) contentType.MobileEditFormUrl = definition.MobileEditFormUrl;
				//if (!string.IsNullOrEmpty(definition.MobileNewFormUrl)) contentType.MobileNewFormUrl = definition.MobileNewFormUrl;
				//if (!string.IsNullOrEmpty(definition.NewDocumentControl)) contentType.NewDocumentControl = definition.NewDocumentControl;
				//if (!string.IsNullOrEmpty(definition.NewFormTemplateName)) contentType.NewFormTemplateName = definition.NewFormTemplateName;
				//if (!string.IsNullOrEmpty(definition.NewFormUrl)) contentType.NewFormUrl = definition.NewFormUrl;			
			}

			return contentType;
		}
	}
}
